#!/usr/bin/env node
// 指定使用 node 解释器运行此脚本

import { Server } from '@modelcontextprotocol/sdk/server/index.js';
// 导入 MCP SDK 中的 Server 类，用于创建 MCP 服务器

import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
// 导入 StdioServerTransport，用于通过标准输入输出与 MCP 客户端通信

import {
  CallToolRequestSchema,
  ErrorCode,
  ListToolsRequestSchema,
  McpError,
} from '@modelcontextprotocol/sdk/types.js';
// 导入 MCP 相关的类型定义和错误处理

import { config } from 'dotenv';
// 导入 dotenv 配置，用于加载环境变量

import fetch from 'node-fetch';
// 导入 fetch，用于发送 HTTP 请求

// 加载环境变量
config();

// 定义 Apifox 配置接口
interface ApifoxConfig {
  token: string;      // Apifox 授权令牌
  projectId: string;  // 项目 ID
  branchId: string;   // 分支 ID
}

// 定义 API 接口
interface ApifoxApi {
  id: number;         // API ID
  name: string;       // API 名称
  type: string;       // API 类型
  method: string;     // HTTP 方法
  path: string;       // API 路径
  folderId: number;   // 文件夹 ID
  tags: string[];     // 标签
  status: string;     // 状态
  responsibleId: number; // 负责人 ID
  customApiFields: any;  // 自定义字段
  visibility: string;    // 可见性
  editorId: number;      // 编辑者 ID
}

// 定义 API 树节点接口
interface ApiTreeNode {
  key: string;        // 节点 key
  type: string;       // 节点类型
  name: string;       // 节点名称
  children?: ApiTreeNode[]; // 子节点
  api?: ApifoxApi;    // API 信息
  folder?: any;       // 文件夹信息
}

// 类型守卫函数：检查错误对象是否包含 message 属性
// 用于更安全地处理错误信息
function isErrorWithMessage(error: unknown): error is { message: string } {
  return (
    typeof error === 'object' &&
    error !== null &&
    'message' in error &&
    typeof (error as Record<string, unknown>).message === 'string'
  );
}

// 辅助函数：获取错误消息
// 如果错误对象有 message 属性则返回该属性，否则将错误转为字符串
function getErrorMessage(error: unknown): string {
  if (isErrorWithMessage(error)) {
    return error.message;
  }
  return String(error);
}

// Apifox 服务器类：实现 MCP 协议的 Apifox 工具服务
class ApifoxServer {
  private server: Server;                    // MCP 服务器实例
  private config: ApifoxConfig | null = null; // Apifox 配置信息
  private apiTreeCache: ApiTreeNode[] | null = null; // API 树缓存
  private isApiTreeLoading: boolean = false; // API 树加载状态
  private apiMappingCache: {
    byId: Map<string, ApifoxApi>,
    byName: Map<string, ApifoxApi>,
    byPath: Map<string, ApifoxApi>
  } = {
    byId: new Map(),
    byName: new Map(),
    byPath: new Map()
  };

  // 构造函数：初始化 MCP 服务器
  constructor() {
    // 创建 MCP 服务器实例，设置名称和版本
    this.server = new Server(
      {
        name: 'apifox-server',
        version: '1.0.0',
      },
      {
        capabilities: {
          tools: {}, // 定义服务器能力
        },
      }
    );

    // 设置工具处理器
    this.setupToolHandlers();
    
    // 错误处理
    this.server.onerror = (error) => console.error('[MCP Error]', error);
    
    // 监听 SIGINT 信号（Ctrl+C），优雅关闭服务
    process.on('SIGINT', async () => {
      await this.cleanup();
      process.exit(0);
    });
  }

  // 清理资源：关闭 MCP 服务器
  private async cleanup() {
    await this.server.close();
  }

  // 确保 Apifox 配置存在
  // 如果未配置，则抛出错误
  private ensureConfig() {
    if (!this.config) {
      throw new McpError(
        ErrorCode.InvalidRequest,
        'Apifox configuration not set. Use connect_apifox tool first.'
      );
    }
    return this.config;
  }

  // 设置工具处理器：定义可用的工具和对应的处理函数
  private setupToolHandlers() {
    // 处理工具列表请求：返回所有可用工具的定义
    this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
      tools: [
        {
          name: 'connect_apifox',
          description: '连接到 Apifox',
          inputSchema: {
            type: 'object',
            properties: {
              token: {
                type: 'string',
                description: 'Apifox 授权令牌 (Bearer Token)',
              },
              projectId: {
                type: 'string',
                description: 'Apifox 项目 ID',
              },
              branchId: {
                type: 'string',
                description: 'Apifox 分支 ID',
              },
            },
            required: ['token', 'projectId', 'branchId'],
          },
        },
        {
          name: 'get_api',
          description: '获取 API 详情',
          inputSchema: {
            type: 'object',
            properties: {
              apiId: {
                type: 'string',
                description: 'API ID',
              },
              apiName: {
                type: 'string',
                description: 'API 名称',
              },
              apiPath: {
                type: 'string',
                description: 'API 路径',
              },
              apiMethod: {
                type: 'string',
                description: 'API HTTP 方法',
                enum: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'],
              },
            },
            required: [],
          },
        }
      ],
    }));

    // 处理工具调用请求：根据工具名称分发到对应的处理函数
    this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
      switch (request.params.name) {
        case 'connect_apifox':
          return await this.handleConnectApifox(request.params.arguments);
        case 'get_api':
          return await this.handleGetApi(request.params.arguments);
        default:
          throw new McpError(
            ErrorCode.MethodNotFound,
            `未知工具: ${request.params.name}`
          );
      }
    });
  }

  // 处理连接 Apifox 请求
  private async handleConnectApifox(args: any) {
    // 检查必要的参数是否存在
    if (!args.token || !args.projectId || !args.branchId) {
      throw new McpError(
        ErrorCode.InvalidParams,
        '缺少必要的 Apifox 配置参数'
      );
    }

    // 保存 Apifox 配置
    this.config = {
      token: args.token,
      projectId: args.projectId,
      branchId: args.branchId,
    };

    try {
      // 只验证连接而不获取 API 树
      const config = this.config;
      const url = `https://api.apifox.com/api/v1/projects/${config.projectId}/api-tree-list?locale=zh-CN&limit=1`;
      
      // 创建 AbortController 用于设置超时
      const controller = new AbortController();
      const timeoutId = setTimeout(() => controller.abort(), 5000); // 5秒超时
      
      const response = await fetch(url, {
        method: 'GET',
        headers: {
          'accept': '*/*',
          'accept-language': 'zh-CN',
          'access-control-allow-origin': '*',
          'authorization': `Bearer ${config.token}`,
          'origin': 'https://app.apifox.com',
          'referer': 'https://app.apifox.com/',
          'x-branch-id': config.branchId,
          'x-client-mode': 'web',
          'x-client-version': '2.6.50-alpha.2',
          'x-device-id': 'apifox-mcp-client',
          'x-project-id': config.projectId,
          'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36'
        },
        signal: controller.signal // 使用 AbortController 信号
      });
      
      clearTimeout(timeoutId); // 清除超时定时器

      if (!response.ok) {
        throw new Error(`Apifox API 请求失败: ${response.status} ${response.statusText}`);
      }
      
      return {
        content: [
          {
            type: 'text',
            text: '成功连接到 Apifox，API 树将在后台异步加载',
          },
        ],
      };
    } catch (error) {
      throw new McpError(
        ErrorCode.InternalError,
        `连接 Apifox 失败: ${getErrorMessage(error)}`
      );
    }
  }

  // 处理获取 API 请求
  private async handleGetApi(args: any) {
    // 确保已连接到 Apifox
    this.ensureConfig();
    
    // 检查参数
    if (!args.apiId && !args.apiName && !args.apiPath && !args.apiMethod) {
      throw new McpError(
        ErrorCode.InvalidParams,
        '必须提供 apiId、apiName、apiPath 或 apiMethod 参数中的至少一个'
      );
    }
    
    try {
      const config = this.ensureConfig();
      
      // 直接通过 ID 获取 API 详情
      if (args.apiId) {
        const apiId = args.apiId;
        const url = `https://api.apifox.com/api/v1/api-details/${apiId}?locale=zh-CN`;
        
        // 创建 AbortController 用于设置超时
        const controller = new AbortController();
        const timeoutId = setTimeout(() => controller.abort(), 10000); // 10秒超时
        
        try {
          const response = await fetch(url, {
            method: 'GET',
            headers: {
              'accept': '*/*',
              'accept-language': 'zh-CN',
              'access-control-allow-origin': '*',
              'authorization': `Bearer ${config.token}`,
              'origin': 'https://app.apifox.com',
              'referer': 'https://app.apifox.com/',
              'x-branch-id': config.branchId,
              'x-client-mode': 'web',
              'x-client-version': '2.6.50-alpha.2',
              'x-device-id': 'apifox-mcp-client',
              'x-project-id': config.projectId,
              'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36'
            },
            signal: controller.signal
          });
          
          clearTimeout(timeoutId);
  
          if (!response.ok) {
            throw new Error(`获取 API 详情失败: ${response.status} ${response.statusText}`);
          }
  
          const detailData = await response.json();
          
          // 返回完整的 API 详情
          return {
            content: [
              {
                type: 'text',
                text: JSON.stringify(detailData, null, 2),
              },
            ],
          };
        } catch (error) {
          clearTimeout(timeoutId);
          throw error;
        }
      }
      
      // 对于其他参数，仍然需要查找 API
      let api: ApifoxApi | null = null;
            
      // 如果未找到 API
      if (!api) {
        return {
          content: [
            {
              type: 'text',
              text: `未找到 API: ${args.apiName || args.apiPath || args.apiMethod}`,
            },
          ],
        };
      }
      
      // 获取完整的 API 详情
      const apiId = args.apiId;
      const url = `https://api.apifox.com/api/v1/api-details/${apiId}?locale=zh-CN`;
      
      const response = await fetch(url, {
        method: 'GET',
        headers: {
          'accept': '*/*',
          'accept-language': 'zh-CN',
          'access-control-allow-origin': '*',
          'authorization': `Bearer ${config.token}`,
          'origin': 'https://app.apifox.com',
          'referer': 'https://app.apifox.com/',
          'x-branch-id': config.branchId,
          'x-client-mode': 'web',
          'x-client-version': '2.6.50-alpha.2',
          'x-device-id': 'apifox-mcp-client',
          'x-project-id': config.projectId,
          'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36'
        }
      });

      if (!response.ok) {
        throw new Error(`获取 API 详情失败: ${response.status} ${response.statusText}`);
      }

      const detailData = await response.json();
      
      // 返回完整的 API 详情
      return {
        content: [
          {
            type: 'text',
            text: JSON.stringify(detailData, null, 2),
          },
        ],
      };
    } catch (error) {
      throw new McpError(
        ErrorCode.InternalError,
        `获取 API 详情失败: ${getErrorMessage(error)}`
      );
    }
  }

  // 运行服务器
  async run() {
    // 创建标准输入输出传输层
    const transport = new StdioServerTransport();
    // 连接服务器到传输层
    await this.server.connect(transport);
    console.error('Apifox MCP server running on stdio');
  }
}

// 创建并运行 Apifox 服务器实例
const server = new ApifoxServer();
server.run().catch(console.error);
